"""
命令处理器模块

这个模块负责实际执行各种命令。
每个命令都实现为CommandHandler类中的一个方法。
"""
from typing import Any, List, Optional, Tuple
import os
from src.config import GlobalConfig
from src.utils.runtime_state import RuntimeState
import json
import subprocess
import shutil
import threading
import sys
import time
from src.utils.context_distill import process_file
from src.web.app import run_web_server

class CommandHandler:
    """
    命令处理器类
    
    负责执行所有支持的命令。
    每个命令都实现为以_cmd_开头的方法。
    """
    
    def execute(self, command: str, args: Optional[List[str]] = None) -> Any:
        """
        执行指定的命令
        
        Args:
            command: 要执行的命令名称
            args: 命令的参数列表
            
        Returns:
            命令执行的结果
            
        Raises:
            ValueError: 当命令不存在时
        """
        method = getattr(self, f"_cmd_{command}", None)
        if method is None:
            raise ValueError(f"未知命令: {command}")
            
        return method(args) if args else method()
        
    def _cmd_list(self, args: Optional[List[str]] = None) -> dict:
        """
        显示当前索引的文件内容
        
        用法：
            list        - 显示所有索引文件的内容
            
        Returns:
            包含索引内容的字典
        """
        from src.utils.context_loader import ContextLoader
        
        try:
            content = ContextLoader.get_directory_tree()
            if not content:
                return {
                    "message": "没有找到索引文件",
                    "status": "empty"
                }
            
            return content
            
        except Exception as e:
            return {
                "message": "读取索引文件失败",
                "status": "error",
                "error": str(e)
            }
        
    def _cmd_pwd(self, args: Optional[List[str]] = None) -> dict:
        """
        显示当前工作目录
        
        Args:
            args: 可选的参数列表
            
        Returns:
            包含当前工作目录的字典
        """
        return  GlobalConfig.get_work_dir()
        
    def _cmd_conf(self, args: Optional[List[str]] = None) -> dict:
        """
        设置或显示配置项
        
        用法：
            conf            - 显示所有配置
            conf key=value  - 设置配置项
            
        Args:
            args: 配置项参数列表
            
        Returns:
            包含配置信息的字典
            
        Raises:
            ValueError: 当参数格式错误时
        """
        # 如果没有参数，显示所有配置
        if not args:
            return {
                "message": "当前配置",
                "config": GlobalConfig.get_all_config()
            }
        
        # 处理配置项设置
        updates = {}
        errors = []
        
        for arg in args:
            # 检查参数格式
            if '=' not in arg:
                errors.append(f"无效的配置项格式: {arg}")
                continue
            
            key, value = arg.split('=', 1)
            key = key.strip()
            value = value.strip()
            
            if not key:
                errors.append("配置项键名不能为空")
                continue
            
            try:
                GlobalConfig.set_config(key, value)
                updates[key] = value
            except Exception as e:
                errors.append(f"设置配置项失败 {key}={value}: {str(e)}")
        
        return {
            "message": "配置更新完成" if updates else "无配置更新",
            "updates": updates,
            "errors": errors if errors else None
        }
        
    def _spin_animation(self):
        """显示转圈圈的动画"""
        spinner = ['|', '/', '-', '\\']
        while getattr(self, '_running', True):
            for symbol in spinner:
                sys.stdout.write(f'\r{symbol} 正在处理...')
                sys.stdout.flush()
                time.sleep(0.1)

    def _cmd_code(self, args: Optional[List[str]] = None) -> dict:
        """
        处理代码相关的命令
        
        用法：
            code <text> [@tag]
            
        Args:
            args: 命令参数列表
            
        Returns:
            包含处理结果的字典
        """
        if not args:
            return {
                "message": "请提供代码描述",
                "usage": "code <text> [@tag]"
            }
        
        # 启动转圈圈动画
        self._running = True
        spinner_thread = threading.Thread(target=self._spin_animation)
        spinner_thread.daemon = True  # 使线程在主线程退出时自动结束
        spinner_thread.start()

        from src.utils.context_loader import ContextLoader
        all_files = ContextLoader.collect_file_paths(GlobalConfig.get_work_dir())
        from src.cli import CodeTagCompleter
        CodeTagCompleter.add_tags(all_files)
        
        # 1. 获取工作目录
        _work_dir = GlobalConfig.get_work_dir()
        if not _work_dir:
            raise ValueError("工作目录未设置")

        # 分离文本和标签
        text_parts = []
        tags = []
        raw_text = ''
        for part in args:
            if part.startswith('@'):
                tags.append(part[1:])  # 去掉@前缀
                raw_text = raw_text +' ' + ('项目文件' + os.path.join(_work_dir, part[1:])) 
            else:
                text_parts.append(part)
                raw_text = raw_text +' ' + part

        from src.utils.api_utils import ApiClient
        # 创建ApiClient实例
        api_client = ApiClient()

        try:
            cache_dir = GlobalConfig.get_config('cache_dir')
            _cache_dir = os.path.join(GlobalConfig.get_work_dir(), cache_dir) 
            from src.utils.file_utils import FileUtils
            FileUtils.ensure_dir_exists(_cache_dir)
            
            _auto_choose_context = GlobalConfig.get_config('auto_choose_context')
            if _auto_choose_context == 'false':
                # 2. 获取索引文件内容
                from src.utils.context_loader import ContextLoader
                _files_content = ContextLoader.get_indexed_context()
            else:
                from src.utils.prompt_utils import generate_choose_context_prompt
                _choose_context_prompt = generate_choose_context_prompt(raw_text)
                # 将 _files_choosed 写入到 choose_context_prompt.txt
                choose_context_file = os.path.join(_cache_dir, 'choose_context_prompt.txt')
                try:
                    with open(choose_context_file, 'w', encoding='utf-8') as f:
                        f.write(_choose_context_prompt)
                except Exception as e:
                    return {
                        "message": "写入choose_context_prompt.txt失败",
                        "status": "error",
                        "error": str(e)
                    }
                _files_choosed = api_client.get_completion(
                    prompt=_choose_context_prompt,
                    system_message="You are a helpful programming assistant. You should provide clear and concise code suggestions."
                )
                
                from src.utils.llm_parser import LLMParser
                _files_choosed = LLMParser.extract_file_paths(_files_choosed)
                print('related files:')
                for file in _files_choosed:
                    print(file)

                from src.utils.context_loader import ContextLoader
                _files_content = ContextLoader.get_files_content(_files_choosed)

            # 3. 获取项目结构
            _project_struct = ContextLoader.get_directory_tree(_work_dir)
            
            # 4. 生成完整prompt
            from src.utils.prompt_utils import generate_complete_prompt
            full_prompt = generate_complete_prompt(
                _work_dir=_work_dir,
                _project_struct=_project_struct,
                _files_content= 'current no files' if _files_content == '' else _files_content,
                _user_prompt=raw_text
            )
            
            # 将 full_prompt 写入到工作目录下的 prompt.txt
            prompt_file = os.path.join(_cache_dir, 'prompt.txt')
            try:
                with open(prompt_file, 'w', encoding='utf-8') as f:
                    f.write(full_prompt)
            except Exception as e:
                return {
                    "message": "写入prompt文件失败",
                    "status": "error",
                    "error": str(e),
                    "text": " ".join(text_parts),
                    "tags": tags,
                    "raw_text": raw_text,
                    "full_prompt": full_prompt
                }
        
            
            # 调用src\utils\api_utils.py的get_completion
            try:       
                # 获取聊天响应
                response = api_client.get_completion(
                    prompt=full_prompt,
                    system_message="You are a helpful programming assistant. You should provide clear and concise code suggestions."
                )
                # response = response.replace('python复制', 'python复制\n\n')
                # response = response.replace('>>>>>>> REPLACE', '>>>>>>> REPLACE\n')
            except Exception as e:
                return {
                    "message": "获取AI响应失败",
                    "status": "error",
                    "error": str(e),
                    "text": " ".join(text_parts),
                    "tags": tags,
                    "raw_text": raw_text,
                    "prompt_file": prompt_file
                }
            finally:
                 # 停止转圈圈动画
                self._running = False
                spinner_thread.join(timeout=0)  # 等待线程结束

            # 将响应写入到工作目录下的output.txt
            output_file = os.path.join(_cache_dir, 'response.txt')
            try:
                with open(output_file, 'w', encoding='utf-8') as f:
                    f.write(response)
                RuntimeState.set('response', response)
            except Exception as e:
                return {
                    "message": "写入响应文件失败",
                    "status": "error",
                    "error": str(e),
                    "text": " ".join(text_parts),
                    "tags": tags,
                    "raw_text": raw_text,
                    "prompt_file": prompt_file,
                    "response": response
                }

            # 解析response中的SEARCH/REPLACE blocks
            from src.utils.block_utils import BlockExtractor
            blocks = BlockExtractor.parse_search_replace_blocks(response)
            modified_files = []
            if len(blocks) == 0:
                raise Exception(response) 
            # 遍历blocks，执行代码
            for block in blocks:
                file_path, search_content, replace_content = block
                # 根据_work_dir和file_path获取文件全路径
                if file_path.find(_work_dir) == -1:
                    file_path = os.path.join(_work_dir, file_path)
                # 判断search_content是否有文本内容，如果有则读取file_path对应文件的代码，将文件中的search_content内容替换成replace_content。
                # 如果没有，则创建编码为utf-8的文件file_path，并将replace_content写入到文件中。
                FileUtils.ensure_dir_exists(file_path)
                if search_content:
                    try:
                        with open(file_path, 'r', encoding='utf-8') as file:
                            content = file.read()
                            pos =  content.find(search_content)
                            if pos != -1:
                                modified_content = content.replace(search_content, replace_content)
                                with open(file_path, 'w', encoding='utf-8') as file:
                                    file.write(modified_content)
                        if replace_content == '' or replace_content is None:
                            os.remove(file_path)
                        continue
                    except FileNotFoundError:
                        with open(file_path, 'w', encoding='utf-8') as file:
                            file.write(replace_content)
                else:
                    with open(file_path, 'w', encoding='utf-8') as file:
                        file.write(replace_content)
                modified_files.append(file_path)
            RuntimeState.set('commit_message', BlockExtractor.extract_commit_message(response))
            RuntimeState.set('modified_files', modified_files)
            GlobalConfig.set_result(blocks)

            from src.review.review import review
            try:
                if not GlobalConfig.get_web_running():
                    if len(blocks) > 0:
                        review()
            except Exception as e:
                return {
                    "message": "代码变更review失败",
                    "status": "error",
                    "error": str(e)
                }
            finally:
                # 停止转圈圈动画
                self._running = False
                spinner_thread.join(timeout=0)  # 等待线程结束
            return {
                "message": "代码命令执行成功",
                "text": " ".join(text_parts),
                "tags": tags,
                "raw_text": raw_text,
                "prompt_file": prompt_file,
                "response": response,
                "output_file": output_file
            }
            
        except Exception as e:
            # 停止转圈圈动画
            self._running = False
            spinner_thread.join(timeout=0)  # 等待线程结束
            return {
                "message": "代码命令执行失败",
                "status": "error",
                "error": str(e),
                "text": " ".join(text_parts),
                "tags": tags,
                "raw_text": raw_text
            }
        finally:
            # 停止转圈圈动画
            self._running = False
            spinner_thread.join(timeout=0)  # 等待线程结束
        
    def _cmd_ref(self, args: Optional[List[str]] = None) -> dict:
        """
        添加或删除上下文引用
        
        用法：
            ref                 - 显示所有引用
            ref url=<url>      - 添加引用
            ref -d url=<url>   - 删除引用
            ref -c             - 清空所有引用
            
        示例：
            ref url=http://test.com file=/path/to/file        # 添加引用
            ref -d url=http://test.com                        # 删除引用
            ref -c                                            # 清空所有引用
            
        Args:
            args: 引用参数列表，格式为 [-d|-c] [key=value]
            
        Returns:
            包含处理结果的字典
        """
        if not args:
            # 显示当前引用的逻辑保持不变...
            references_str = GlobalConfig.get_config('references')
            if references_str:
                try:
                    current_refs = json.loads(references_str)
                    return {
                        "message": "当前引用列表",
                        "references": current_refs
                    }
                except json.JSONDecodeError:
                    return {
                        "message": "当前没有有效的引用",
                        "references": {}
                    }
            return {
                "message": "当前没有引用",
                "references": {}
            }

        # 检查是否是清空操作
        if args[0] == '-c':
            if len(args) > 1:
                return {
                    "message": "清空命令不需要其他参数",
                    "usage": "ref -c"
                }
            # 清空引用
            try:
                GlobalConfig.set_config('references', '{}')
                return {
                    "message": "已清空所有引用",
                    "references": {}
                }
            except Exception as e:
                return {
                    "message": "清空引用失败",
                    "error": str(e)
                }

        # 检查是否是删除操作
        is_delete = False
        if args[0] == '-d':
            is_delete = True
            args = args[1:]  # 移除-d参数
            if not args:
                return {
                    "message": "请提供要删除的引用",
                    "usage": "ref -d <type>=<value>"
                }

        # 获取现有引用
        current_refs_str = GlobalConfig.get_config('references')
        try:
            current_refs = json.loads(current_refs_str) if current_refs_str else {}
        except json.JSONDecodeError:
            current_refs = {}

        # 处理引用参数
        new_references = {}
        deleted_references = {}
        errors = []
        
        # 支持的引用类型
        valid_types = {'url', 'file', 'folder'}

        for arg in args:
            # 检查参数格式
            if '=' not in arg:
                errors.append(f"无效的引用格式: {arg}")
                continue
            
            ref_type, value = arg.split('=', 1)
            ref_type = ref_type.strip().lower()
            value = value.strip()
            
            # 验证引用类型
            if ref_type not in valid_types:
                errors.append(f"未知的引用类型: {ref_type}")
                continue
            
            # 验证值不能为空
            if not value:
                errors.append(f"引用值不能为空: {ref_type}=")
                continue

            if is_delete:
                # 删除操作
                if ref_type not in current_refs:
                    errors.append(f"引用类型 {ref_type} 不存在")
                    continue
                
                if value not in current_refs[ref_type]:
                    errors.append(f"引用值 {value} 不存在于 {ref_type} 中")
                    continue
                
                # 记录要删除的引用
                if ref_type not in deleted_references:
                    deleted_references[ref_type] = []
                deleted_references[ref_type].append(value)
                
                # 从列表中删除值
                current_refs[ref_type].remove(value)
                
                # 如果列表为空，删除该类型
                if not current_refs[ref_type]:
                    del current_refs[ref_type]
            else:
                # 添加操作的验证逻辑...
                if ref_type == 'url':
                    if not (value.startswith('http://') or value.startswith('https://')):
                        errors.append(f"无效的URL格式: {value}")
                        continue
                elif ref_type in ('file', 'folder'):
                    try:
                        abs_path = os.path.abspath(os.path.expanduser(value))
                        if ref_type == 'file' and not os.path.isfile(abs_path):
                            errors.append(f"文件不存在: {value}")
                            continue
                        elif ref_type == 'folder' and not os.path.isdir(abs_path):
                            errors.append(f"目录不存在: {value}")
                            continue
                        value = abs_path
                    except Exception as e:
                        errors.append(f"路径处理错误 {value}: {str(e)}")
                        continue

                # 添加新引用
                if ref_type not in new_references:
                    new_references[ref_type] = []
                new_references[ref_type].append(value)

        if not is_delete:
            # 合并现有引用和新引用
            for ref_type, values in new_references.items():
                if ref_type not in current_refs:
                    current_refs[ref_type] = []
                # 添加新值，避免重复
                current_refs[ref_type].extend(v for v in values if v not in current_refs[ref_type])

        # 保存更新后的引用到配置文件
        try:
            GlobalConfig.set_config('references', json.dumps(current_refs))
        except Exception as e:
            errors.append(f"保存引用到配置文件失败: {str(e)}")

        # 准备返回结果
        if is_delete:
            result = {
                "message": "引用删除成功" if deleted_references else "无引用被删除",
                "deleted": deleted_references,
                "references": current_refs  # 返回更新后的引用列表
            }
        else:
            result = {
                "message": "引用添加成功" if new_references else "无有效引用被添加",
                "references": current_refs
            }

        if errors:
            result["errors"] = errors

        return result 
        
    def _check_git_repo(self, path: str) -> Tuple[bool, str]:
        """
        检查目录是否已经是git仓库
        
        Args:
            path: 要检查的目录路径
            
        Returns:
            (bool, str): (是否是git仓库, 错误信息)
        """
        try:
            # 检查.git目录是否存在
            if os.path.exists(os.path.join(path, '.git')):
                return True, ""
            
            # 运行git rev-parse来确认
            result = subprocess.run(
                ['git', 'rev-parse', '--git-dir'],
                cwd=path,
                capture_output=True,
                text=True
            )
            
            return result.returncode == 0, ""
        except subprocess.CalledProcessError as e:
            return False, str(e)
        except Exception as e:
            return False, str(e)
    
    def _cmd_init(self, args: Optional[List[str]] = None) -> dict:
        """
        初始化git仓库
        
        用法：
            init        - 在当前工作目录初始化git仓库
            
        Returns:
            包含初始化结果的字典
        """
        work_dir = GlobalConfig.get_work_dir()
        if not work_dir:
            return {
                "message": "工作目录未设置",
                "status": "error"
            }
        
        # 检查是否已经是git仓库
        is_repo, error = self._check_git_repo(work_dir)
        if error:
            return {
                "message": f"检查git仓库状态失败: {error}",
                "status": "error"
            }
        
        if is_repo:
            return {
                "message": "目录已经是git仓库",
                "status": "skipped",
                "path": work_dir
            }
        
        # 执行git init
        try:
            result = subprocess.run(
                ['git', 'init'],
                cwd=work_dir,
                capture_output=True,
                text=True
            )
            
            if result.returncode == 0:
                return {
                    "message": "Git仓库初始化成功",
                    "status": "success",
                    "path": work_dir,
                    "output": result.stdout.strip()
                }
            else:
                return {
                    "message": "Git仓库初始化失败",
                    "status": "error",
                    "error": result.stderr.strip()
                }
                
        except subprocess.CalledProcessError as e:
            return {
                "message": "Git命令执行失败",
                "status": "error",
                "error": str(e)
            }
        except Exception as e:
            return {
                "message": "初始化过程中发生错误",
                "status": "error",
                "error": str(e)
            } 
        
    def _create_directory_path(self, path: str) -> None:
        """
        递归创建路径中的目录
        
        Args:
            path: 完整的文件或目录路径
            
        注意：
            - 如果path是文件路径，只会创建其所在的目录
            - 如果path是目录路径，会创建整个目录路径
        """
        # 获取目录路径（如果path是文件路径，则获取其所在目录）
        directory = os.path.dirname(path) if os.path.splitext(path)[1] else path
        
        # 如果目录不存在，则递归创建
        if directory and not os.path.exists(directory):
            try:
                os.makedirs(directory)
            except Exception as e:
                raise Exception(f"创建目录失败 {directory}: {str(e)}")

    def _cmd_index(self, args: Optional[List[str]] = None) -> dict:
        """
        对工作目录中的文件进行索引
        
        用法：
            index        - 索引工作目录中的所有Python文件
            
        Returns:
            包含索引结果的字典
        """
        work_dir = GlobalConfig.get_work_dir()
        if not work_dir:
            return {
                "message": "工作目录未设置",
                "status": "error"
            }

        # 创建.index目录
        index_dir = os.path.join(work_dir, '.index')
        # 如果目录存在则先删除再创建
        if os.path.exists(index_dir):
            shutil.rmtree(index_dir)
        try:
            os.makedirs(index_dir, exist_ok=True)
        except Exception as e:
            return {
                "message": "创建索引目录失败",
                "status": "error",
                "error": str(e)
            }
        
        # 递归遍历目录
        processed_files = []
        errors = []
        

        
        # 启动转圈圈动画
        self._running = True
        spinner_thread = threading.Thread(target=self._spin_animation)
        spinner_thread.daemon = True  # 使线程在主线程退出时自动结束
        spinner_thread.start()

        # 开始处理
        try:
            from src.utils.context_loader import ContextLoader
            project_type = GlobalConfig.get_config('project_type')
            dir_skip, file_skip = ContextLoader.get_file_scan_skips(project_type)
            processed_files = ContextLoader.collect_paths(work_dir, dir_skip, file_skip)
            processed_files = [os.path.join(work_dir, file) for file in processed_files]
            process_file(processed_files)
            result = {
                "message": "索引完成",
                "status": "success",
                "processed_files": processed_files,
                "processed_count": len(processed_files)
            }
            
            if errors:
                result["errors"] = errors
                result["status"] = "partial"
            # 停止转圈圈动画
            self._running = False
            spinner_thread.join(timeout=0)  # 等待线程结束
            return result
            
        except Exception as e:
            return {
                "message": "索引过程中发生错误",
                "status": "error",
                "error": str(e)
            }
        finally:
            # 停止转圈圈动画
            self._running = False
            spinner_thread.join(timeout=0)  # 等待线程结束
        
        
    def _cmd_commit(self, args: Optional[List[str]] = None) -> dict:
        """
        执行git commit命令
        
        用法：
            commit        - 使用RuntimeState中的commit_message执行git commit
            
        Returns:
            包含执行结果的字典
        """
        work_dir = GlobalConfig.get_work_dir()
        if not work_dir:
            return {
                "message": "工作目录未设置",
                "status": "error"
            }
        
        # 获取commit message
        commit_message = RuntimeState.get('commit_message')
        if not commit_message:
            return {
                "message": "没有需要commit的内容，未找到commit message",
                "status": "error"
            }
        
        try:
            # 设置环境变量，确保git使用utf-8编码
            env = os.environ.copy()
            env['PYTHONIOENCODING'] = 'utf-8'
            
            # 先执行git add .
            add_result = subprocess.run(
                ['git', 'add', '.'],
                cwd=work_dir,
                capture_output=True,
                text=True,
                encoding='utf-8',  # 指定编码为utf-8
                env=env  # 使用修改后的环境变量
            )
            
            if add_result.returncode != 0:
                return {
                    "message": "git add失败",
                    "status": "error",
                    "error": add_result.stderr
                }
            
            # 执行git commit
            commit_result = subprocess.run(
                ['git', 'commit', '-m', commit_message],
                cwd=work_dir,
                capture_output=True,
                text=True,
                encoding='utf-8',  # 指定编码为utf-8
                env=env  # 使用修改后的环境变量
            )
            
            if commit_result.returncode == 0:
                if GlobalConfig.get_config('auto_choose_context') == 'true':
                    print('开始对修改文件重建索引，请稍等...')
                    modified_files = RuntimeState.get('modified_files')
                    # 更新索引- 摘要总结
                    process_file(modified_files, clear_cache_file=False)
                    print('完成修改文件索引重建')
                return {
                    "message": "Git commit执行成功",
                    "status": "success",
                    "commit_message": commit_message,
                    "output": commit_result.stdout
                }
            else:
                return {
                    "message": "Git commit执行失败",
                    "status": "error",
                    "error": commit_result.stderr or commit_result.stdout
                }
                
        except subprocess.CalledProcessError as e:
            return {
                "message": "Git命令执行失败",
                "status": "error",
                "error": str(e)
            }
        except Exception as e:
            return {
                "message": "执行过程中发生错误",
                "status": "error",
                "error": str(e)
            } 
        
    def _cmd_rollback(self, args: Optional[List[str]] = None) -> dict:
        """
        回滚工作目录到最后一次commit的状态
        
        用法：
            rollback    - 回滚所有更改到最后一次commit
            
        Returns:
            包含执行结果的字典
        """
        work_dir = GlobalConfig.get_work_dir()
        if not work_dir:
            return {
                "message": "工作目录未设置",
                "status": "error"
            }
            
        try:
            # 设置环境变量，确保git使用utf-8编码
            env = os.environ.copy()
            env['PYTHONIOENCODING'] = 'utf-8'
            
            # 先检查是否有未提交的更改
            status_result = subprocess.run(
                ['git', 'status', '--porcelain'],
                cwd=work_dir,
                capture_output=True,
                text=True,
                encoding='utf-8',  # 指定编码为utf-8
                env=env  # 使用修改后的环境变量
            )
            
            if status_result.returncode != 0:
                return {
                    "message": "检查git状态失败",
                    "status": "error",
                    "error": status_result.stderr
                }
            
            if not status_result.stdout.strip():
                return {
                    "message": "没有需要回滚的更改",
                    "status": "skipped"
                }
            
            # 执行git reset --hard HEAD
            reset_result = subprocess.run(
                ['git', 'reset', '--hard', 'HEAD'],
                cwd=work_dir,
                capture_output=True,
                text=True,
                encoding='utf-8',  # 指定编码为utf-8
                env=env  # 使用修改后的环境变量
            )
            
            if reset_result.returncode == 0:
                # 清除运行时状态
                RuntimeState.delete('commit_message')
                RuntimeState.delete('response')
                
                return {
                    "message": "成功回滚到最后一次commit",
                    "status": "success",
                    "output": reset_result.stdout
                }
            else:
                return {
                    "message": "回滚失败",
                    "status": "error",
                    "error": reset_result.stderr
                }
                
        except subprocess.CalledProcessError as e:
            return {
                "message": "Git命令执行失败",
                "status": "error",
                "error": str(e)
            }
        except Exception as e:
            return {
                "message": "执行过程中发生错误",
                "status": "error",
                "error": str(e)
            } 
        
    def _cmd_rag(self, args: Optional[List[str]] = None) -> dict:
        """
        管理RAG资源
        
        用法：
            rag                     - 显示所有RAG资源
            rag <name> <path>       - 添加或更新RAG资源
            rag -d <name>          - 删除指定RAG资源
            rag -c                 - 清空所有RAG资源
            
        Args:
            args: 命令参数列表
                无参数: 显示所有资源
                两个参数: <name> <path> 添加或更新资源
                两个参数: -d <name> 删除资源
                一个参数: -c 清空所有资源
                
        Returns:
            包含执行结果的字典
            
        示例:
            rag cse_doc /src/docs  # 添加cse_doc资源，指向/src/docs目录
            rag -d cse_doc         # 删除cse_doc资源
            rag -c                 # 清空所有资源
        """
        from src.utils.file_utils import FileUtils

        rag_resource_path = os.path.join(GlobalConfig.get_config('cache_dir'), 'rag_resources.json')
            
        # 获取当前的RAG资源配置
        rag_resources = RuntimeState.get('rag_resources', {})
        if not rag_resources:
            if os.path.exists(rag_resource_path):
                with open(rag_resource_path, 'r', encoding='utf-8') as f:
                    rag_resources = json.load(f)
                RuntimeState.set('rag_resources', rag_resources)
        
        # 如果没有参数，显示所有资源
        if not args:
            if not rag_resources:
                return {
                    "message": "当前没有RAG资源",
                    "status": "empty"
                }
            return {
                "message": "当前RAG资源列表",
                "status": "success",
                "resources": rag_resources
            }
        
        # 清空所有资源
        if args[0] == '-c':
            for name in rag_resources:
                if name in rag_resources and 'index_path' in rag_resources[name]:
                    if rag_resources[name]['index_path'] is not None and os.path.exists(rag_resources[name]['index_path']):
                        os.remove(rag_resources[name]['index_path'])
            RuntimeState.set('rag_resources', {})
            os.remove(rag_resource_path)
            return {
                "message": "已清空所有RAG资源",
                "status": "success"
            }
        
        # 删除指定资源
        if args[0] == '-d':
            if len(args) != 2:
                return {
                    "message": "删除资源需要指定资源名称",
                    "status": "error",
                    "usage": "rag -d <name>"
                }
            name = args[1]
            if name not in rag_resources:
                return {
                    "message": f"资源 {name} 不存在",
                    "status": "error"
                }
            
            if name in rag_resources and 'index_path' in rag_resources[name]:
                if rag_resources[name]['index_path'] is not None and os.path.exists(rag_resources[name]['index_path']):
                    os.remove(rag_resources[name]['index_path'])
            del rag_resources[name]
            RuntimeState.set('rag_resources', rag_resources)
            FileUtils.write_text_to_file(rag_resource_path, json.dumps(rag_resources))   
            return {
                "message": f"已删除资源 {name}",
                "status": "success"
            }
        
        # 添加或更新资源
        if len(args) != 2:
            return {
                "message": "添加或更新资源需要指定资源名称和路径",
                "status": "error",
                "usage": "rag <name> <path>"
            }
        
        name, path = args
        
        if not os.path.exists(path):
            return {
                "message": f"路径不存在: {path}",
                "status": "error"
            }
        
        # 更新资源
        if name in rag_resources:
            if rag_resources[name]['index_path'] and os.path.exists(rag_resources[name]['index_path']):
                os.remove(rag_resources[name]['index_path'])
            rag_resources[name]['index_path'] = None
            # TODO: 删除索引文件后，需要重新生成索引
        else:
            rag_resources[name] = {
                "path": path,
                "index_path": None,
                "type": FileUtils.detect_resource_type(path)
            }
        RuntimeState.set('rag_resources', rag_resources)
        from src.utils.file_utils import FileUtils
        FileUtils.write_text_to_file(rag_resource_path, json.dumps(rag_resources))
        return {
            "message": f"已{'更新' if name in rag_resources else '添加'}资源 {name}",
            "status": "success",
            "resource": {
                "name": name
            }
        } 

    def _cmd_web(self, args: Optional[List[str]] = None) -> dict:
        """
        启动Web服务器
        
        用法：
            web        - 启动Web服务器，监听7777端口
            
        Returns:
            包含执行结果的字典
        """
        try:
            run_web_server()
            GlobalConfig.set_web_running(True)
            return {
                "message": "Web服务器已启动",
                "status": "success",
                "port": 7777
            }
        except Exception as e:
            return {
                "message": "启动Web服务器失败",
                "status": "error",
                "error": str(e)
            } 

    def _cmd_sw(self, args: Optional[List[str]] = None) -> dict:
        """
        切换当前使用的ini配置文件
        
        用法：
            sw <config_path>  - 切换到指定的ini配置文件
            
        Args:
            args: 配置文件路径
            
        Returns:
            包含切换结果的字典
        """
        if not args or len(args) != 1:
            return {
                "message": "请提供配置文件路径",
                "status": "error",
                "usage": "sw <config_path>"
            }
        
        config_path = args[0]
        
        try:
            # 调用GlobalConfig的init方法切换配置文件
            GlobalConfig.init(config_path)
            return {
                "message": "成功切换配置文件",
                "status": "success",
                "config_path": config_path
            }
        except Exception as e:
            return {
                "message": "切换配置文件失败",
                "status": "error",
                "error": str(e)
            } 
        

    def _cmd_desc(self) -> dict:
        """
        生成项目描述，用户大模型解析项目代码

        """
        _work_dir = GlobalConfig.get_work_dir()
        cache_dir = GlobalConfig.get_config('cache_dir')
        _cache_dir = os.path.join(GlobalConfig.get_work_dir(), cache_dir) 
        from src.utils.file_utils import FileUtils
        FileUtils.ensure_dir_exists(_cache_dir)
        from src.utils.context_loader import ContextLoader
        _files_content = ContextLoader.get_indexed_context()

        # 3. 获取项目结构
        _project_struct = ContextLoader.get_directory_tree(_work_dir)
            
        # 将 项目描述信息 写入到工作目录下的 ask.txt
        from src.utils.prompt_utils import generate_ask_prompt
        ask_file = os.path.join(_cache_dir, 'ask.txt')
        try:
            ask_prompt = generate_ask_prompt(
            _work_dir=_work_dir,
            _project_struct=_project_struct,
            _files_content= 'current no files' if _files_content == '' else _files_content
            )
            with open(ask_file, 'w', encoding='utf-8') as f:
                f.write(ask_prompt)
            return {
                "message": "写入ask文件成功",
                "status": "success",
                "ask_file": ask_file
            }
        except Exception as e:
            return {
                "message": "写入ask文件失败",
                "sttus": "error",
                    "error": str(e)
            }

    def _cmd_chat(self, args: Optional[List[str]] = None) -> dict:
        """
        与LLM进行对话
        
        用法：
            chat <session_name>=<message>  - 在指定会话中发送消息
            
        Args:
            args: 命令参数，格式为 ["session_name=message"]
            
        Returns:
            包含对话结果的字典
            
        示例:
            chat test=你好     # 在test会话中发送"你好"
        """
        args = [' '.join(args)]
        if not args or len(args) != 1 or '=' not in args[0]:
            return {
                "message": "请提供正确的会话名称和消息",
                "status": "error",
                "usage": "chat <session_name>=<message>"
            }
            
        # 解析会话名称和消息
        session_name, message = args[0].split('=', 1)
        session_name = session_name.strip()
        message = message.strip()
        
        if not session_name or not message:
            return {
                "message": "会话名称和消息不能为空",
                "status": "error"
            }
            
        try:
            # 获取缓存目录
            cache_dir = GlobalConfig.get_config('cache_dir')
            _cache_dir = os.path.join(GlobalConfig.get_work_dir(), cache_dir)
            
            # 确保缓存目录存在
            from src.utils.file_utils import FileUtils
            FileUtils.ensure_dir_exists(_cache_dir)
            
            # 构建会话历史文件路径
            history_file = os.path.join(_cache_dir, f"{session_name}.txt")
            
            # 读取会话历史
            session_history = []
            if os.path.exists(history_file):
                try:
                    with open(history_file, 'r', encoding='utf-8') as f:
                        content = f.read()
                        if content:
                            session_history = json.loads(content)
                            if not isinstance(session_history, list):
                                session_history = []
                except (json.JSONDecodeError, Exception):
                    session_history = []
            
            # 创建API客户端
            from src.utils.api_utils import ApiClient
            api_client = ApiClient()
            
            # 调用API获取回复
            response = api_client.get_completion(
                prompt=message,
                history_messages=session_history
            )
            
            # 更新会话历史
            session_history.append({"role": "user", "content": message})
            session_history.append({"role": "assistant", "content": response})
            
            # 保存会话历史到文件
            try:
                with open(history_file, 'w', encoding='utf-8') as f:
                    json.dump(session_history, f, ensure_ascii=False, indent=2)
            except Exception as e:
                return {
                    "message": "保存会话历史失败",
                    "status": "error",
                    "error": str(e)
                }
                
            # 使用CodeFormatter格式化响应中的代码
            from src.utils.code_formatter import CodeFormatter
            formatted_response = CodeFormatter.format_text(response)
            return [formatted_response, response]

        except Exception as e:
            return {
                "message": "对话过程中发生错误",
                "status": "error",
                "error": str(e)
            }